#include "stm32f10x.h"                  // Device header
#include <Delay.h>
#include "ADC_DATA.h"

#define T25 298.15    //电压转温度的公式的采用
#define R25 10
#define B	3435

uint16_t AD0,AD1;
/**
  * 函    数：AD初始化
  * 参    数：无
  * 返 回 值：无
  */
void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//开启ADC1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	
	
	/*设置ADC时钟*/
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//选择时钟6分频，ADCCLK = 72MHz / 6 = 12MHz
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA3、PA4引脚初始化为模拟输入
	
	/*不在此处配置规则组序列，而是在每次AD转换前配置，这样可以灵活更改AD转换的通道*/
	
	/*ADC初始化*/
	ADC_InitTypeDef ADC_InitStructure;						//定义结构体变量
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;		//模式，选择独立模式，即单独使用ADC1
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;		//数据对齐，选择右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//外部触发，使用软件触发，不需要外部触发
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;		//连续转换，失能，每转换一次规则组序列后停止
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;				//扫描模式，失能，只转换规则组的序列1这一个位置
	ADC_InitStructure.ADC_NbrOfChannel = 1;					//通道数，为1，仅在扫描模式下，才需要指定大于1的数，在非扫描模式下，只能是1
	ADC_Init(ADC1, &ADC_InitStructure);						
	
	/*ADC使能*/
	ADC_Cmd(ADC1, ENABLE);									//使能ADC1，ADC开始运行
	
	/*ADC校准*/
	ADC_ResetCalibration(ADC1);								//固定流程，内部有电路会自动执行校准
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while (ADC_GetCalibrationStatus(ADC1) == SET);
}

/**
  * 函    数：获取AD转换的值
  * 参    数：ADC_Channel 指定AD转换的通道，范围：ADC_Channel_x，其中x可以是0/1/2/3
  * 返 回 值：AD转换的值，范围：0~4095
  */
uint16_t AD_GetValue(uint8_t ADC_Channel)
{
	ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);	//在每次转换前，根据函数形参灵活更改规则组的通道1
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);					//软件触发AD转换一次
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);	//等待EOC标志位，即等待AD转换结束
	return ADC_GetConversionValue(ADC1);					//读数据寄存器，得到AD转换的结果
	Delay_ms(10);
}

void GetADCNumber(void)
{
	AD0 = AD_GetValue(ADC_Channel_3);  //单次启动ADC，转换通道3
	AD1 = AD_GetValue(ADC_Channel_4); //单次启动ADC，转换通道4
	Delay_ms(50);
}

/**
  * 函    数：模拟量转电阻阻值
  * 参    数：ADCT,采集的模拟量
  * 返 回 值：电阻阻值
  */
float Get_ADC_R(uint16_t ADC)
{
	//单片机3.3v供电，先求出电压
	float v1 = (float)(ADC*3.3)/4095;//ntc上的电压
	float v2 = 3.3 - v1;
	float r = (v1/v2)*10;
	
	return r;
}

/**
  * 函    数：实现ln(x) 的计算
  * 参    数：A 需要运算的值
  * 返 回 值：运算结果
  */
double Myln(double a)
{
   int N = 15;//取了前15+1项来估算
   int k,nk;
   double x,xx,y;
   x = (a-1)/(a+1);
   xx = x*x;
   nk = 2*N+1;
   y = 1.0/nk;
   for(k=N;k>0;k--)
   {
     nk = nk - 2;
     y = 1.0/nk+xx*y;
     
   }
   return 2.0*x*y;
}

//温度采集模块

/**
  * 函    数：将读取的AD值转换为温度值
  * 参    数：ADC 采集的数字量
  * 返 回 值：N4 摄氏温度
  */

float Get_Kelvin_Temperature(uint16_t ADC)
{
	float N1,N2,N3,N4;
	float Rntc = Get_ADC_R(ADC);
	N1 = (Myln(R25)-Myln(Rntc))/B;
	N2 = 1/T25 - N1;
	N3 = 1/N2;
	N4 = N3-273.15;//开尔文转摄氏度
	
	return N4;
}

/**
  * 函    数：将读取的温度值转换为字符型数组
  * 参    数：buffer[] 储存数组
  * 参    数：ADC 采集的数字量
  * 返 回 值：无
  */
void GetADCTem(char buffer[], uint16_t ADC) 
{
    float Num;
    int IntegerPart, Digit0, Digit1, Digit2; // 整数 十位 个位 小数
    Num = Get_Kelvin_Temperature(ADC);
    
    IntegerPart = (int)Num; // 获取整数部分
    float FractionPart = Num - IntegerPart; // 获取小数部分

    if (FractionPart < 0) // 确保小数部分为正数
	{ 
        FractionPart = -FractionPart;
    }

    Digit0 = (IntegerPart / 10) % 10; // 获取十位数
    Digit1 = IntegerPart % 10; // 获取个位
    Digit2 = (int)(FractionPart * 10) % 10; // 获取小数第一位

    // 需要5个字符空间，两个数字、小数点、一位小数和终止符'\0'
    buffer[0] = '0' + Digit0; // 将数字转换为ASCII字符
    buffer[1] = '0' + Digit1;
    buffer[2] = '.';
    buffer[3] = '0' + Digit2;
    buffer[4] = '\0'; // 字符串终止符
}




